import { createService } from './request'
/**
 * 全局分页配置
 */
export const paginationConfig = { pageSize: 10, pageNum: 1 }

const service = createService(
  {
    baseURL: '/',
    timeout: 6000,
    headers: {
      'Content-type': 'application/json'
    }
  },
  {
    request: config => config,
    response: [
      data => {
        console.log(data)

        return Promise.resolve(data)
      },
      error => {
        return Promise.reject(error)
      }
    ]
  }
)

/**
 * @template T
 * @param {import('axios').AxiosRequestConfig} data
 * @returns {Promise<T extends Blob ? { blob: Blob; filename: string } : T>}
 */
export function request(data) {
  return service.request(data).then(response => response.data)
}

/**
 * 异步store注册 获取 store实例
 * @template T
 *
 * @param {import('vuex').Store} store
 * @param {string} modulePath
 * @param {T} module
 * @returns {any}
 */
export function getModule(store, modulePath, module) {
  if (store.hasModule(modulePath)) return store.state[modulePath]
  store.registerModule(modulePath, module)
  return store.state[modulePath]
}

class Sub {
  constructor() {
    /**
     * @type {Record<string, Function[]>}
     */
    this.handles = Object.create(null)
  }

  /**
   * 添加监听事件
   *
   * @param {keyof HTMLElementEventMap} eventType
   * @param {Function} handle
   * @memberof Sub
   */
  on(eventType, handle) {
    if (!Object.prototype.hasOwnProperty.call(this.handles, eventType)) {
      this.handles[eventType] = []
    }

    if (typeof handle === 'function') {
      this.handles[eventType].push(handle)
    } else {
      throw Error('缺少回调函数')
    }

    return this
  }

  /**
   * 添加监听事件
   *
   * @param {keyof HTMLElementEventMap} eventType
   * @param {Function} handle
   * @memberof Sub
   */
  once(eventType, handle) {
    console.log(eventType, this.handles[eventType])
    const fn = (...args) => {
      handle.apply(null, args)
      this.off(eventType, fn)
    }

    this.on(eventType, fn)
    console.log(eventType, this.handles[eventType])
    return this
  }

  /**
   * 触发监听事件
   * @param {string} eventType
   * @param {any[]} args
   */
  emit(eventType, ...args) {
    if (Object.prototype.hasOwnProperty.call(this.handles, eventType)) {
      this.handles[eventType].forEach(handle => {
        handle.apply(null, args)
      })
    } else {
      throw new Error(`"${eventType}"事件未注册`)
    }

    return this
  }

  /**
   * 移除监听事件
   *
   * @param {keyof HTMLElementEventMap} eventType
   * @param {Function} handle
   * @memberof Sub
   */
  off(eventType, handle) {
    if (!Object.prototype.hasOwnProperty.call(this.handles, eventType)) {
      throw new Error(`"${eventType}"事件未注册`)
    } else if (typeof handle != 'function') {
      throw Error('缺少回调函数')
    } else {
      this.handles[eventType].forEach((item, index, arr) => {
        if (item === handle) {
          arr.splice(index, 1)
        }
      })
    }
  }
}

/**
 *
 * @export
 * @class LoadScript
 * @extends {Sub}
 */
export class LoadScript extends Sub {
  /**
   * @param {string} url
   * @param {object} options
   * @param {string} [options.type]
   * @param {string} [options.charset]
   * @param {true} [options.async]
   */
  constructor(url, options = Object.assign({ type: 'text/javascript', charset: 'utf8', async: true })) {
    super()
    this.url = url

    this.options = options

    this.el = this.createElement()

    this.el && this.addEventListener(this.el)
  }

  createElement() {
    const el = document.createElement('script')

    /**
     * @type {boolean}
     */
    const haveLoadScript = Object.prototype.hasOwnProperty.call(LoadScript.loads, this.url)

    if (haveLoadScript) {
      if (LoadScript.loads[this.url].getAttribute('load') !== 'load') {
        console.warn(`已有script ${this.url} 正在加载`)
        this.addEventListener(LoadScript.loads[this.url])
        return
      }

      if (LoadScript.loads[this.url].getAttribute('load') === 'load') {
        if (Promise) {
          Promise.resolve().then(() => this.emit('load'))
        } else {
          setTimeout(() => this.emit('load'), 0)
        }

        console.warn(`已有script ${this.url} 加载完毕`)
        return
      }
    }

    LoadScript.loads[this.url] = el

    el.src = this.url
    el.async = this.options.async
    el.charset = this.options.charset
    el.type = this.options.type
    return el
  }

  /**
   *
   * @param {HTMLScriptElement} el
   */
  addEventListener(el) {
    el.addEventListener('load', () => {
      this.emit('load', this)
      if (!el.getAttribute('load')) el.setAttribute('load', 'load')
    })

    document.getElementsByTagName('head')[0].appendChild(el)
  }
}

/**
 *
 * @static loads
 * @type {Record<string, HTMLScriptElement>}
 */
LoadScript.loads = Object.create(null)
